<#include "license.ftl">
<@license/>
<#assign object = doc.object>
package ${object.@package}.service.base;

import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.HashMap;
import java.util.HashSet;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.SEVERE;
import java.util.logging.Logger;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import redora.service.BusinessRuleViolation;
import redora.service.ServletBase;
import redora.api.fetch.*;
import ${object.@package}.model.*;
import ${object.@package}.service.*;
import ${object.@package}.sql.base.${object.@name}SQLBase.DefaultFinder;
import redora.util.JSONWriter;
<#if doc["//enum[@scope='global']"][0]??>
import ${object.@package}.model.enums.*;
</#if>

/**
* This servlet dispatches standard retrieve / insert / update and delete operations on the ${object.@name} object.
* This class is extended by ${object.@name}Servlet, so if you want to modify the behavior of this class, please change that file.
* @author Redora (www.redora.net)
* @see ${object.@package}.service.http.${object.@name}Servlet;
*/
public class ${object.@name}ServletBase extends ServletBase {
    static final transient Logger l = Logger.getLogger("${object.@package}.service.base.${object.@name}ServletBase");

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        doGet(req, resp, null);
    }

    /**
     * The DefaultFinder query has a _p request parameter like _p=param1,param2,etc.
     * If appendParam is not null, this value will be appended.
     */
    protected void doGet(HttpServletRequest req, HttpServletResponse resp, Long appendParam)
            throws ServletException, IOException {
        JSONWriter writer = new JSONWriter(resp);

        ${object.@name}ServiceJSON ${object.@name?uncap_first}ServiceJSON = null;
        try {
            ${object.@name?uncap_first}ServiceJSON = ServiceFactory.${object.@name?uncap_first}ServiceJSON();
            if (req.getParameter("_df") != null) {
                StringBuilder p = new StringBuilder(req.getParameter("_p") == null ? "" : req.getParameter("_p"));
                if (appendParam != null) {
                    if (p.length() > 0)
                        p.append(',');
                    p.append(appendParam);
                }
                ${object.@name?uncap_first}ServiceJSON.finder(
                        DefaultFinder.values()[Integer.parseInt(req.getParameter("_df"))]
                        , p.toString(), page(req), writer);
            } else if (req.getParameter("_fid") != null) {
                ${object.@name?uncap_first}ServiceJSON.findById(Long.valueOf(req.getParameter("_fid")), page(req).getScope(), writer);
            } else if (req.getParameter("_fids") != null) {
                Map<Scope, Set<Long>> ids = new HashMap<Scope, Set<Long>>();
                for (String idScope : req.getParameter("_fids").split(",")) {
                    Scope scope = Scope.values()[Integer.parseInt(idScope.split(":")[0])];
                    if (!ids.containsKey(scope)) {
                        ids.put(scope, new HashSet<Long>());
                    }
                    ids.get(scope).add(Long.valueOf(idScope.split(":")[1]));
                }
                ${object.@name?uncap_first}ServiceJSON.findById(ids, writer);
<#if object.lazyScope[0]??>
            } else if ("fetchLazy".equalsIgnoreCase(req.getParameter("_operationType"))) {
                ${object.@name?uncap_first}ServiceJSON.fetchLazy(Long.valueOf(req.getParameter("id")), writer);
</#if>
            } else {
                l.log(SEVERE, "Useless parameter(s) for request: {0}", req.getQueryString());
                throw new ServletException("I failed to process a JSON request: " + req.getQueryString());
            }
            writer.flush();
        } catch (Exception e) {
            l.log(SEVERE, "I failed to process a JSON request: " + req.getQueryString(), e);
            throw new ServletException("I failed to process a JSON request: " + req.getQueryString(), e);
        } finally {
            ServiceFactory.close(${object.@name?uncap_first}ServiceJSON);
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        JSONWriter writer = new JSONWriter(resp);

        ${object.@name}ServiceJSON ${object.@name?uncap_first}ServiceJSON = null;
        ${object.@name}Service ${object.@name?uncap_first}Service = null;
        try {
            ${object.@name?uncap_first}ServiceJSON = ServiceFactory.${object.@name?uncap_first}ServiceJSON();
            if ("persist".equalsIgnoreCase(req.getParameter("_operationType"))) {
                ${object.@name} ${object.@name?uncap_first} = ${object.@name}Util.from(req);
                ${object.@name?uncap_first}Service = ServiceFactory.${object.@name?uncap_first}Service();
                Set<BusinessRuleViolation> ret = ${object.@name?uncap_first}Service.persist(${object.@name?uncap_first});
                if (ret.isEmpty()) {
                    writer.responseStart();
                    ${object.@name}Util.copy(${object.@name?uncap_first}, writer);
                    writer.responseEnd();
                } else {
                    l.log(INFO, "Responding {0} violated business rules", ret.size());
                    writer.violation(ret);
                }
            } else if ("delete".equalsIgnoreCase(req.getParameter("_operationType"))) {
                ${object.@name?uncap_first}Service = ServiceFactory.${object.@name?uncap_first}Service();
                Set<BusinessRuleViolation> ret = new HashSet<BusinessRuleViolation>();
                for (String id : req.getParameter("id").split(",")) {
                    ${object.@name} ${object.@name?uncap_first} = ${object.@name?uncap_first}Service.findById(Long.valueOf(id), Scope.List);
                    ret.addAll(${object.@name?uncap_first}Service.delete(${object.@name?uncap_first}));
                }
                ServiceFactory.close(${object.@name?uncap_first}Service);
                writer.persist(ret);
<#list doc["/object/attributes/set[@multiplicity='n-to-m']"] as att>
            } else if ("connectTo${att.@class?cap_first}".equalsIgnoreCase(req.getParameter("_operationType"))) {
                ${object.@name?uncap_first}Service = ServiceFactory.${object.@name?uncap_first}Service();
                String ${att.@myName}Ids[] = req.getParameter("${att.@myName}Id").split(",");
                for (String ${att.@myName}Id : ${att.@myName}Ids) {
                    String ${att.@theirName}Ids[] = req.getParameter("${att.@theirName}Id").split(",");
    <#if att.@sorted == "both" || att.@sorted == "them">
                    int sort = ${object.@name?uncap_first}Service.countConnectionsTo${att.@class}(Long.valueOf(${att.@myName}Id));
    </#if>
                    for (String ${att.@theirName}Id : ${att.@theirName}Ids) {
                        ${object.@name?uncap_first}Service.connectTo${att.@class}(Long.valueOf(${att.@myName}Id), Long.valueOf(${att.@theirName}Id)<#if att.@sorted == "both" || att.@sorted == "them">, sort</#if>, false);
    <#if att.@sorted == "both" || att.@sorted == "them">
                        sort++;
    </#if>
                    }
                }
                writer.responseSuccess();
            } else if ("deleteRelationWith${att.@class}".equalsIgnoreCase(req.getParameter("_operationType"))) {
                ${object.@name?uncap_first}Service = ServiceFactory.${object.@name?uncap_first}Service();
                String ${att.@myName}Ids[] = req.getParameter("${att.@myName}Id").split(",");
                for (String ${att.@myName}Id : ${att.@myName}Ids) {
                    String ${att.@theirName}Ids[] = req.getParameter("${att.@theirName}Id").split(",");
                    for (String ${att.@theirName}Id : ${att.@theirName}Ids) {
                        ${object.@name?uncap_first}Service.deleteRelationWith${att.@class}(Long.valueOf(${att.@myName}Id), Long.valueOf(${att.@theirName}Id), false);
                    }
                }
                writer.responseSuccess();
            <#if att.@sorted == "both" || att.@sorted == "me">
            } else if ("moveBy${att.@class}".equalsIgnoreCase(req.getParameter("_operationType"))) { //sorted: ${att.@sorted}
                ${object.@name?uncap_first}Service = ServiceFactory.${object.@name?uncap_first}Service();
                ${att.@class}Service ${att.@class?uncap_first}Service = new ${att.@class}Service(${object.@name?uncap_first}Service);
                ${att.@class} ${att.@class?uncap_first} = ${att.@class?uncap_first}Service.findById(
                        Long.valueOf(req.getParameter("${att.@class?uncap_first}Id")), Scope.Table);
                int position = Integer.parseInt(req.getParameter("position"));
                ${object.@name} moveObj = null;
                for (${object.@name} pojo : ${att.@class?uncap_first}.get${object.plural}()) {
                    if (pojo.getId().equals(Long.valueOf(req.getParameter("id")))) {
                        //moveObj = pojo;
                        ${att.@class?uncap_first}.get${object.plural}().move(pojo, position);
                        break;
                    }
                }
                //TODO remove after check function
                //${att.@class?uncap_first}.get${object.@name}s().move(moveObj, position);
                //${object.@name}Service _${object.@name?uncap_first}Service = ServiceFactory.${object.@name?uncap_first}Service();
                ${att.@class?uncap_first}Service.persist(${att.@class?uncap_first});
           </#if>
</#list>
<#list doc["/object/attributes/set[@multiplicity='1-to-n' and @sorted='true']"] as att>
            } else if ("move${att.@class}By${object.@name}".equalsIgnoreCase(req.getParameter("_operationType"))) {
                ${object.@name?uncap_first}Service = ServiceFactory.${object.@name?uncap_first}Service();
                ${object.@name} ${object.@name?uncap_first} = ${object.@name?uncap_first}Service.findById(
                        Long.valueOf(req.getParameter("${object.@name?uncap_first}Id")), Scope.Table);
                int position = Integer.parseInt(req.getParameter("position"));
                ${att.@class} temp = null;
                for (${att.@class} pojo : ${object.@name?uncap_first}.get${att.@fieldName?cap_first}()) {
                    if (pojo.getId().equals(Long.valueOf(req.getParameter("id")))) {
                        ${object.@name?uncap_first}.get${att.@fieldName?cap_first}().move(pojo, position);
                        //temp = pojo;
                        break;
                    }
                }
                //${object.@name?uncap_first}.get${att.@fieldName?cap_first}().move(temp, position);
                ${object.@name?uncap_first}Service.persist(${object.@name?uncap_first});
</#list>
<#if object.trashcan == "true">
            } else if ("trash".equalsIgnoreCase(req.getParameter("_operationType"))) {
                Set<BusinessRuleViolation> ret = new HashSet<BusinessRuleViolation>();
                ${object.@name?uncap_first}Service = ServiceFactory.${object.@name?uncap_first}Service();
                for (String id : req.getParameter("id").split(",")) {
                    ${object.@name} ${object.@name?uncap_first} = ${object.@name?uncap_first}Service.findById(Long.valueOf(id), Scope.List);
                    ret.addAll(${object.@name?uncap_first}Service.trash(null, ${object.@name?uncap_first}));
                }
                writer.persist(ret);
            } else if ("undo".equalsIgnoreCase(req.getParameter("_operationType"))) {
                String ids[] = req.getParameter("id").split(",");
                ${object.@name?uncap_first}Service = ServiceFactory.${object.@name?uncap_first}Service();
                for (String id : ids) {
                    ${object.@name?uncap_first}Service.undo(Long.valueOf(id));
                }
                writer.responseSuccess();
</#if>
            } else if ("dropTable".equalsIgnoreCase(req.getParameter("_operationType"))) {
                Upgrade up = new Upgrade();
                up.drop("${object.@name}", true, false);  //TODO remove this handle
                up.close();
            }
            writer.flush();
        } catch (Exception e) {
            l.log(SEVERE, "I failed to process a JSON request: " + req.getQueryString(), e);
            throw new ServletException("I failed to process a JSON request: " + req.getQueryString(), e);
        } finally {
            ServiceFactory.close(${object.@name?uncap_first}ServiceJSON);
            ServiceFactory.close(${object.@name?uncap_first}Service);
        }
    }
}
